﻿namespace Summoner
{
    using UnityEngine;
    using UnityEditor;
    using System.IO;
    using System.Collections.Generic;
#if !UNITY_5_3
    using UnityEngine.Profiling;
#endif

    [CustomEditor(typeof(AssetVessel))]
    public class AssetVesselInspector : Editor
    {
        private AssetVessel _target = null;
        private Vector2 _scrollPos = Vector2.zero;

        private void OnEnable()
        {
            if(this._target == null)
            {
                this._target = this.target as AssetVessel;
            }
        }

        public override void OnInspectorGUI()
        {
            if(this._target.assetList.Count == 0)
            {
                if(GUILayout.Button("Add folder assets"))
                {
                    string path = this.GetAssetPath();
                    if (!string.IsNullOrEmpty(path))
                    {
                        this.AddFolderAssets(path);
                    }
                }
            }
            else
            {
                if (GUILayout.Button("Refresh"))
                {
                    this.UpdateList();
                }
                GUILayout.BeginHorizontal();
                if(GUILayout.Button("Add folder assets"))
                {
                    string path = this.GetAssetPath();
                    if (!string.IsNullOrEmpty(path))
                    {
                        this.AddFolderAssets(path);
                    }
                }
                if (GUILayout.Button("Remove folder assets"))
                {
                    string path = this.GetAssetPath();
                    if (!string.IsNullOrEmpty(path))
                    {
                        this.RemoveFolderAssets(path);
                    }
                }
                GUILayout.EndHorizontal();
            }
            if(this._target.repeatList.Count > 0)
            {
                this.DrawRepeats();
            }
            else
            {
                this.DrawStatusbar();
                this.DrawAssetList();
            }
        }

        private string FilterPath(string str)
        {
            int index = str.IndexOf("Assets");
            if(index > 0)
            {
                return str.Substring(index);
            }
            return str;
        }

        private string FilterName(string str)
        {
            int index = str.IndexOf("-");
            if (index > 0)
            {
                return str.Substring(0, index);
            }
            return str;
        }

        private bool DoNotFilter(string path)
        {
            foreach(string str in AssetEditUntil.FilterExtensions)
            {
                if (path.ToLower().EndsWith(str.ToLower()))
                {
                    return false;
                }
            }
            return true;
        }
        private void UpdateList()
        {
            for (int i = 0; i < this._target.assetList.Count; i++)
            {
                if (this._target.assetList[i].asset == null)
                {
                    this._target.assetList[i].asset = AssetDatabase.LoadAssetAtPath(this._target.assetList[i].pathInEditor, System.Type.GetType(this._target.assetList[i].type));
                    if (this._target.assetList[i].asset == null)
                    {
                        this._target.assetList.RemoveAt(i);
                    }
                }
                else
                {
                    this._target.assetList[i].pathInEditor = AssetDatabase.GetAssetPath(this._target.assetList[i].asset);
                    this._target.assetList[i].Md5 = MD5Hashing.GetFileHash(this._target.assetList[i].pathInEditor);
                }
            }
            EditorUtility.SetDirty(this._target);
            AssetDatabase.SaveAssets();
        }

        /// <summary>
        /// get all assets
        /// </summary>
        private void AddFolderAssets(string path)
        {
            this.UpdateList();
            Dictionary<string, AssetInfo> path2info = CreatePathDictionary(this._target.assetList);
            foreach (AssetInfo info in DoScanAssetPath(path))
            {
                if (!path2info.ContainsKey(info.pathInEditor.Replace("\\", "/")))
                {
                    this._target.assetList.Add(info);
                }
            }
            AssetEditUntil.CheckRepeat();
        }

        private void RemoveFolderAssets(string path)
        {
            this.UpdateList();
            Dictionary<string, AssetInfo> path2info = CreatePathDictionary(this._target.assetList);
            foreach (AssetInfo info in DoScanAssetPath(path))
            {
                if (path2info.ContainsKey(info.pathInEditor.Replace("\\", "/")))
                {
                    this._target.assetList.Remove(path2info[info.pathInEditor.Replace("\\", "/")]);
                }
            }
            AssetEditUntil.CheckRepeat();
        }

        private List<AssetInfo> DoScanAssetPath(string folder)
        {
            List<AssetInfo> assetList = new List<AssetInfo>();
            string[] files = Directory.GetFiles(folder, "*.*", System.IO.SearchOption.AllDirectories);
            for (int i = 0; i < files.Length; i++)
            {
                if (this.DoNotFilter(files[i]))
                {
                    string path = this.FilterPath(files[i]);
                    Object obj = AssetDatabase.LoadAssetAtPath(path, typeof(Object));
                    if (obj != null)
                    {
                        assetList.Add(new AssetInfo() { asset = obj, assetName = obj.name, type = obj.GetType().ToString(), pathInEditor = path, Name = FilterName(obj.name), FileSize = (obj.GetType().Equals(typeof(UnityEngine.Texture2D))) ? AssetEditUntil.GetFileSizeOnDisk(obj) : (int)(new FileInfo(path).Length), RamSize = Profiler.GetRuntimeMemorySize(obj), Md5 = MD5Hashing.GetFileHash(files[i]) });
                    }
                }
            }
            return assetList;
        }

        private Dictionary<string, AssetInfo> CreatePathDictionary(List<AssetInfo> infoList)
        {
            Dictionary<string, AssetInfo> path2info = new Dictionary<string, AssetInfo>();
            foreach (AssetInfo info in infoList)
            {
                path2info[info.pathInEditor.Replace("\\", "/")] = info;
            }
            return path2info;
        }

        private string GetAssetPath()
        {
            string str = EditorUtility.OpenFolderPanel("Select an path", "Assets", "");
            if (string.IsNullOrEmpty(str))
            {
                str = Application.dataPath;
            }
            return str;
        }

        private void DrawStatusbar()
        {
            this._target.version = EditorGUILayout.TextField("Version: ", this._target.version);
        }

        private void DrawAssetList()
        {
            if (this._target.assetList.Count > 0)
            {
                this._scrollPos = GUILayout.BeginScrollView(this._scrollPos, "box");
                for (int i = 0; i < this._target.assetList.Count; i++)
                {
                    GUILayout.BeginVertical("box");
                    this._target.assetList[i].isUnfolder = EditorGUILayout.Foldout(this._target.assetList[i].isUnfolder, this._target.assetList[i].assetName);
                    if (this._target.assetList[i].isUnfolder)
                    {
                        this._target.assetList[i].asset = EditorGUILayout.ObjectField("Asset Reference: ", this._target.assetList[i].asset, typeof(Object), false);
                        EditorGUILayout.LabelField("Asset Name: ", this._target.assetList[i].assetName);
                        EditorGUILayout.LabelField("File Size: ", EditorUtility.FormatBytes(this._target.assetList[i].FileSize));
                        EditorGUILayout.LabelField("Ram Size: ", EditorUtility.FormatBytes(this._target.assetList[i].RamSize));
                        EditorGUILayout.LabelField("Asset Type: ", this._target.assetList[i].type);
                        EditorGUILayout.LabelField("Asset Path In Editor: ", this._target.assetList[i].pathInEditor);
                        EditorGUILayout.LabelField("Asset Md5: ", this._target.assetList[i].Md5);
                    }
                    GUILayout.EndVertical();
                }
                GUILayout.EndScrollView();
            }
        }

        private void DrawRepeats()
        {
            GUI.color = Color.yellow;
            foreach (RepeatAsset repeat in this._target.repeatList)
            {
                GUILayout.BeginVertical("box");
                GUILayout.Label("Asset Name: " + repeat.assetName);
                foreach(AssetInfo info in repeat.repeats)
                {
                    GUILayout.BeginHorizontal();
                    EditorGUILayout.ObjectField(info.asset, typeof(Object), false);
                    if(GUILayout.Button("X", GUILayout.Width(30)))
                    {
                        this.RemoveAsset(info);
                        AssetEditUntil.CheckRepeat();
                        return;
                    }
                    GUILayout.EndHorizontal();
                }
                GUILayout.EndVertical();
            }
            GUI.color = Color.white;
        }

        private void RemoveAsset(AssetInfo info)
        {
            Dictionary<string, AssetInfo> path2info = CreatePathDictionary(this._target.assetList);
            if(path2info.ContainsKey(info.pathInEditor.Replace("\\", "/")))
            {
                this._target.assetList.Remove(path2info[info.pathInEditor]);
            }
        }
    }
}